#include "UnityPrefix.h"
#include "Runtime/Scripting/Backend/ScriptingTypes.h"
#include "Runtime/Scripting/ScriptingUtility.h"
#include "Runtime/Scripting/ScriptingManager.h"
#include "Runtime/BaseClasses/GameObject.h"
#include "Runtime/Misc/GameObjectUtility.h"
#include "Runtime/Mono/MonoBehaviour.h"
#include "Runtime/Mono/MonoManager.h"
#include "Runtime/Scripting/Backend/ScriptingBackendApi.h"
#include "Runtime/Scripting/Backend/ScriptingTypeRegistry.h"
#include "Runtime/Scripting/Scripting.h"

#if ENABLE_SCRIPTING

GameObject* MonoCreateGameObject (const char* name)
{
	string cname;
	if (!name)
	{
		cname = "New Game Object";
	}
	else
	{
		cname = name;
	}
	return &CreateGameObject (cname, "Transform", NULL);
}

ScriptingObjectPtr MonoAddComponent (GameObject& go, const char* name)
{
	string error;
	Unity::Component* component = AddComponent (go, name, &error);
	
	if (component)
		return Scripting::ScriptingWrapperFor (component);
	else
	{
		LogStringObject (error, &go);
		return SCRIPTING_NULL;
	}
}

static bool IsNonMonoBehaviourUnityEngineType(ScriptingClassPtr klass)
{
	return !scripting_class_is_subclass_of(klass, MONO_COMMON.monoBehaviour);
}

ScriptingObjectPtr MonoAddComponentWithType (GameObject& go, ScriptingObjectPtr systemTypeInstance, bool dontShareMonoScript)
{
	string error;
	
	
	Unity::Component* component = NULL;
	ScriptingClassPtr klass = GetScriptingTypeRegistry().GetType(systemTypeInstance);

	if (klass == SCRIPTING_NULL)
	{
#if MONO_QUALITY_ERRORS
		ScriptWarning("AddComponent asking for invalid type", &go);
#endif
		return SCRIPTING_NULL;
	}
	int instanceID = go.GetInstanceID();
	if (IsNonMonoBehaviourUnityEngineType(klass))
	{
		int classID = Object::StringToClassID (scripting_class_get_name (klass));
		component = AddComponent (go, classID, NULL, &error);
	}
	else
	{
		MonoScript* script = NULL;
		if (!dontShareMonoScript)
			script = GetMonoScriptManager().FindRuntimeScript (klass);
		if (!script)
			script = CreateMonoScriptFromScriptingType(klass);
		if (script)
			component = AddComponent (go, ClassID (MonoBehaviour), script, &error);
	}
	
	if (component)
		return Scripting::ScriptingWrapperFor(component);
	else
	{
		// Check if the object is still valid ( could have been destroyed in Awake.)
		LogStringObject (error, PPtr<Object> (instanceID));
		return SCRIPTING_NULL;
	}
}
#endif
